package com.benli.voteme.service;

import com.benli.voteme.model.User;
import com.benli.voteme.repository.UserRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

import lombok.extern.slf4j.Slf4j;

import static org.apache.commons.lang3.StringUtils.isNotEmpty;

/**
 * com.benli.voteme.service: Service for providing user manipulations.
 * <p>
 * Date: 2018/4/9 Time: 8:13 PM
 *
 * @author Created by benli
 * @see [CLASS/METHOD](Optional)
 * @since [PRODUCT/MODULE_VERSION](Optional)
 */
@Slf4j
@Service
public class UserService {
    // Private variable for user repository
    private final UserRepository userRepository;

    @Autowired
    public UserService(final UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    /**
     * Save the persistence entity
     *
     * @param paramUser input parameter
     * @return persistence result
     */
    private Optional<User> save(final User paramUser) {
        log.debug("Begin saving user {}", paramUser);
        // Validation

        // Persistence
        try {
            log.debug("End saving user {}", paramUser);
            return Optional.of(userRepository.save(paramUser));
        } catch (Exception paramE) {
            log.error("Error saving user {}", paramUser, paramE);
            return Optional.empty();
        }
    }

    private Optional<User> find(final String paramSerial) {
        log.debug("Begin finding user with serial {}", paramSerial);
        // Validation
        if (isNotEmpty(paramSerial)) {
            User filter = User.builder().id(paramSerial).build();
            return userRepository.findOne(Example.of(filter));
        } else {
            return Optional.empty();
        }
    }

    /**
     * Generic interface for updating one attributes
     *
     * @param paramSerial       entity id
     * @param paramUserConsumer consume function
     */
    private void operateUser(final String paramSerial, Consumer<User> paramUserConsumer) {
        if (isNotEmpty(paramSerial)) {
            find(paramSerial)
                .ifPresent(res -> {
                        // Operate
                        paramUserConsumer.accept(res);
                        // Update
                        save(res);
                    }
                );
        }
    }

    private void operateUser(final String paramSerial, List<Consumer<User>> paramUserConsumerList) {
        if (isNotEmpty(paramSerial)) {
            find(paramSerial)
                .ifPresent(res -> {
                    paramUserConsumerList.forEach(consumer -> consumer.accept(res));
                    save(res);
                });
        }
    }

    void setDeleted(final String paramSerial, final boolean paramResult) {
        operateUser(paramSerial, paramUser -> paramUser.setIsDeleted(paramResult));
    }

    void setDisabled(final String paramSerial, final boolean paramResult) {
        operateUser(paramSerial, paramUser -> paramUser.setIsDisabled(paramResult));
    }
}
